#pragma once

#include "ScriptCompiler/ASTBuilder/ASTBuilder.h"
#include "ScriptCompiler/AST/ExpressionNode.h"

class CExpressionNode;
class CTypeNode;

class CExpressionBuilder : public IASTBuilder
{
public:
    // InEndTokenIndex is the index of the token after the last token of the sentence
    CExpressionBuilder(std::shared_ptr<CScriptFileContext> InContext
        , uint64_t InEndTokenIndex);

    virtual bool ReadCurentToken() override;

    std::shared_ptr<CExpressionNode> Result;

    // token index should < EndTokenIndex, not <=
    uint64_t EndTokenIndex;
protected:
    std::shared_ptr<CScriptFileContext> Context;

    // using RawASTNode= TVariant<std::shared_ptr<CExpressionNode>, std::shared_ptr<CScriptToken>>;
    // std::shared_ptr<CExpressionNode> BuildExpression(const std::list<RawASTNode>& Content);


    enum class EOperator
    {
        //priority 14

        Parentheses, // ( ) 
        Bracket, // [ ]
        Dot, // .
        Arrow, // ->
        Increment, // ++ , at right
        Decrement, // -- , at right

        //priority 13
        
        Positive, // +i
        Negtive, // -i
        Not, // !
        BitNot, // ~
        Dereference, // *
        Sizeof, // sizeof
        AddressOf, // &
        TypeCast, // (type)
        LeftIncrement, // ++ , at left
        LeftDecrement, // -- , at left

        //priority 12

        Multiply, // *
        Divide, // /
        Mod, // %

        //priority 11

        Add, // a+b
        Sub, // a-b

        //priority 10

        LeftShift, // <<
        RightShift, // >>

        //priority 9

        Less, // <
        LessEqual, // <=
        Greater, // >
        GreaterEqual, // >=

        //priority 8

        Equal, // ==
        NotEqual, // !=

        //priority 7

        BitAnd, // &

        //priority 6

        BitXor, // ^

        //priority 5

        BitOr, // |

        //priority 4

        And, // &&

        //priority 3

        Or, // ||

        //priority 2

        Conditional, // ? :

        //priority 1

        Assign, // =
        PlusAssign, // +=
        MinusAssign, // -=
        MultiplyAssign, // *=
        DivideAssign, // /=
        ModAssign, // %=
        LeftShiftAssign, // <<=
        RightShiftAssign, // >>=
        BitAndAssign, // &=
        BitXorAssign, // ^=
        BitOrAssign, // |=

        //priority 0

        Comma, // ,

        //priority -1

        Invalid,
    };

    static int64_t GetOperatorPriority(EOperator Operator)
    {
        switch(Operator)
        {
        case EOperator::Parentheses:
        case EOperator::Bracket:
        case EOperator::Dot:
        case EOperator::Arrow:
        case EOperator::Increment:
        case EOperator::Decrement:
            return 14;
        case EOperator::Positive:
        case EOperator::Negtive:
        case EOperator::Not:
        case EOperator::BitNot:
        case EOperator::Dereference:
        case EOperator::Sizeof:
        case EOperator::AddressOf:
        case EOperator::TypeCast:
        case EOperator::LeftIncrement:
        case EOperator::LeftDecrement:
            return 13;
        case EOperator::Multiply:
        case EOperator::Divide:
        case EOperator::Mod:
            return 12;
        case EOperator::Add:
        case EOperator::Sub:
            return 11;
        case EOperator::LeftShift:
        case EOperator::RightShift:
            return 10;
        case EOperator::Less:
        case EOperator::LessEqual:
        case EOperator::Greater:
        case EOperator::GreaterEqual:
            return 9;
        case EOperator::Equal:
        case EOperator::NotEqual:
            return 8;
        case EOperator::BitAnd:
            return 7;
        case EOperator::BitXor:
            return 6;
        case EOperator::BitOr:
            return 5;
        case EOperator::And:
            return 4;
        case EOperator::Or:
            return 3;
        case EOperator::Conditional:
            return 2;
        case EOperator::Assign:
        case EOperator::PlusAssign:
        case EOperator::MinusAssign:
        case EOperator::MultiplyAssign:
        case EOperator::DivideAssign:
        case EOperator::ModAssign:
        case EOperator::LeftShiftAssign:
        case EOperator::RightShiftAssign:
        case EOperator::BitAndAssign:
        case EOperator::BitXorAssign:
        case EOperator::BitOrAssign:
            return 1;
        case EOperator::Comma:
            return 0;
        case EOperator::Invalid:
            return -1;
        default:
            assert(false&& "unhandled operator");
            return -1;
        }
    }

    //iteral tokens to build expression
    //@InPrority , the priority of the operator that is being processed
    //             if meet a operator with lower priority, will stop
    //return expression
    std::shared_ptr<CExpressionNode> IteralTokens(int64_t InPrority);
};